{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [unfold](https://www.30secondsofcode.org/python/s/unfold)\n",
    "Python, Function, List, Advanced\n",
    "\n",
    "Builds a list, using an iterator function and an initial seed value.\n",
    "\n",
    "The iterator function accepts one argument (`seed`) and must always return a list with two elements ([`value`, `nextSeed`]) or `False` to terminate. Use a generator function, `fn_generator`, that uses a `while` loop to call the iterator function and `yield` the `value` until it returns `False`. Use list comprehension to return the list that is produced by the generator, using the iterator function."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "不理解，构建列表何必如此复杂"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T08:50:53.748621Z",
     "start_time": "2020-08-26T08:50:53.743177Z"
    }
   },
   "outputs": [],
   "source": [
    "def unfold(fn, seed):\n",
    "    def fn_generator(val):\n",
    "        while True: \n",
    "            val = fn(val[1])\n",
    "            print(val)\n",
    "            if val == False: break\n",
    "            yield val[0]\n",
    "    return [i for i in fn_generator([None, seed])]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T08:54:03.120693Z",
     "start_time": "2020-08-26T08:54:03.109992Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-10, 20]\n",
      "[-20, 30]\n",
      "[-30, 40]\n",
      "[-40, 50]\n",
      "[-50, 60]\n",
      "False\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[-10, -20, -30, -40, -50]"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = lambda n: False if n > 50 else [-n, n + 10]\n",
    "unfold(f, 10) # [-10, -20, -30, -40, -50]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [check_prop](https://www.30secondsofcode.org/python/s/check-prop)\n",
    "Python, Function, Intermediate\n",
    "\n",
    "Given a predicate function, `fn`, and a `prop` string, this curried function will then take an object to inspect by calling the property and passing it to the predicate.\n",
    "\n",
    "Return a `lambda` function that takes an object and applies the predicate function, `fn` to the specified property.\n",
    "\n",
    "根据条件判断是否字典是否存在键值对。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:01:41.992788Z",
     "start_time": "2020-08-26T09:01:41.987948Z"
    }
   },
   "outputs": [],
   "source": [
    "def check_prop(fn, prop):\n",
    "    return lambda obj: fn(obj[prop])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T09:01:53.562900Z",
     "start_time": "2020-08-26T09:01:53.552878Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_age = check_prop(lambda x: x >= 18, 'age')\n",
    "user = {'name': 'Mark', 'age': 18}\n",
    "\n",
    "check_age(user) # True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [compose](https://www.30secondsofcode.org/python/s/compose)\n",
    "Python, Function, Intermediate\n",
    "\n",
    "Performs right-to-left function composition.\n",
    "\n",
    "Use `functools.reduce()` to perform right-to-left function composition. The last (rightmost) function can accept one or more arguments; the remaining functions must be unary.\n",
    "\n",
    "从右往左计算并累加\n",
    "\n",
    "`functools.reduce()`：累加；(笔记在：python/functools-moudle/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T10:18:59.742037Z",
     "start_time": "2020-08-26T10:18:59.736916Z"
    }
   },
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "def compose(*fns):\n",
    "    return reduce(lambda f, g: lambda *args: f(g(*args)), fns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T10:28:22.807108Z",
     "start_time": "2020-08-26T10:28:22.799115Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add5 = lambda x: x + 10\n",
    "multiply = lambda x, y: x * y\n",
    "multiply_and_add_5 = compose(add5, multiply)\n",
    "\n",
    "multiply_and_add_5(5, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [compose_right](https://www.30secondsofcode.org/python/s/compose-right)\n",
    "Python, Function, Intermediate\n",
    "\n",
    "Performs left-to-right function composition.\n",
    "\n",
    "Use `functools.reduce()` to perform left-to-right function composition. The first (leftmost) function can accept one or more arguments; the remaining functions must be unary.\n",
    "\n",
    "从左往右计算并累加"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T10:19:23.034484Z",
     "start_time": "2020-08-26T10:19:23.029360Z"
    }
   },
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "def compose_right(*fns):\n",
    "    return reduce(lambda f, g: lambda *args: g(f(*args)), fns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T10:21:43.961563Z",
     "start_time": "2020-08-26T10:21:43.952368Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "49"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add = lambda x, y: x + y\n",
    "square = lambda x: x * x\n",
    "add_and_square = compose_right(add,square)\n",
    "\n",
    "add_and_square(5, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [curry](https://www.30secondsofcode.org/python/s/curry)\n",
    "Python, Function, Intermediate\n",
    "\n",
    "Curries a function.\n",
    "\n",
    "Use `functools.partial()` to return a new partial object which behaves like `fn` with the given arguments, `args`, partially applied.\n",
    "\n",
    "`functools.partial(a,b)`：把b赋值给a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T12:08:14.096618Z",
     "start_time": "2020-08-26T12:08:14.091462Z"
    }
   },
   "outputs": [],
   "source": [
    "from functools import partial\n",
    "\n",
    "def curry(fn, *args):\n",
    "    return partial(fn,*args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T12:08:25.638121Z",
     "start_time": "2020-08-26T12:08:25.630042Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "30"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add = lambda x, y: x + y\n",
    "add10 = curry(add, 10)\n",
    "\n",
    "add10(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T12:10:59.405630Z",
     "start_time": "2020-08-26T12:10:59.400180Z"
    }
   },
   "outputs": [],
   "source": [
    "from time import sleep\n",
    "\n",
    "def delay(fn, ms, *args):\n",
    "    sleep(ms / 1000)\n",
    "    return fn(*args)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [delay](https://www.30secondsofcode.org/python/s/delay)\n",
    "Python, Function, Intermediate\n",
    "\n",
    "Invokes the provided function after `ms` milliseconds.\n",
    "\n",
    "Use `time.sleep()` to delay the execution of `fn` by `ms / 1000` seconds.\n",
    "\n",
    "先休眠后调用函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T12:11:12.315975Z",
     "start_time": "2020-08-26T12:11:11.311130Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "later\n"
     ]
    }
   ],
   "source": [
    "delay(\n",
    "    lambda x: print(x),\n",
    "    1000,\n",
    "    'later'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [when](https://www.30secondsofcode.org/python/s/when)\n",
    "Python, Function, Intermediate\n",
    "\n",
    "Tests a value, `x`, against a `predicate` function, conditionally applying a function.\n",
    "\n",
    "Check if the value of `predicate(x)` is `True` and if so return `when_true(x)`, otherwise return `x`.\n",
    "\n",
    "如果是偶数则返回2倍，否则返回奇数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T12:17:24.806053Z",
     "start_time": "2020-08-26T12:17:24.801143Z"
    }
   },
   "outputs": [],
   "source": [
    "def when(predicate, when_true):\n",
    "    return lambda x: when_true(x) if predicate(x) else x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-26T12:18:03.968470Z",
     "start_time": "2020-08-26T12:18:03.961933Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "double_even_numbers = when(lambda x: x % 2 == 0, lambda x : x * 2)\n",
    "print(double_even_numbers(4))\n",
    "print(double_even_numbers(3))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
